package app.controllers.member;

import app.Const;
import app.constant.MemberConstant;
import app.constant.OrderConstant;
import app.constant.TransferConstant;
import app.kit.SmsCodeKit;
import app.kit.SmsKit;
import app.kit.TypeKit;
import app.models.basic.Notes;
import app.models.member.Account;
import app.models.member.Member;
import app.models.member.MemberProduct;
import app.models.order.Order;
import app.models.product.Product;
import app.models.transfer.TranferMode;
import app.models.transfer.TransferProduct;
import app.models.transfer.TransferRule;
import app.services.OrderService;
import com.google.common.base.Strings;
import com.google.common.collect.Maps;
import com.jfinal.plugin.activerecord.Db;
import com.jfinal.plugin.activerecord.IAtom;
import com.jfinal.plugin.activerecord.Page;
import goja.Logger;
import goja.StringPool;
import goja.Validator;
import goja.mvc.Controller;
import goja.plugins.sqlinxml.SqlKit;
import goja.security.goja.SecurityKit;
import org.apache.commons.lang3.math.NumberUtils;
import org.joda.time.DateTime;

import java.math.BigDecimal;
import java.sql.SQLException;
import java.util.Map;

import static app.Const.FIELD_STATUS;
import static app.Const.FIELD_ORDER_ID;
import static app.constant.MemberConstant.DEFAULT_STATUS;
import static app.constant.MemberConstant.PRODUCT_FOUND;
import static app.constant.MemberConstant.TRANSFER_AUDIT;
import static app.constant.MemberConstant.TRANSFER_AUDIT_SUCCESS;
import static app.constant.MemberConstant.TRANSFER_TRADE_FAIL;
import static app.constant.MemberConstant.TRANSFER_TRADE_SUCCESS;
import static app.models.member.MemberProduct.FIELD_PRODUCT_STATUS;
import static app.models.member.MemberProduct.FIELD_REDEEM_STATUS;
import static app.models.member.MemberProduct.FIELD_TRANSFER_STATUS;
import static app.models.member.MemberProduct.dao;

/**
 * <p>
 * The url member/transfer Controller.
 * </p>
 *
 * @author sagyf yang
 * @version 1.0
 * @since JDK 1.6
 */
public class TransferController extends Controller {

    /**
     * The index route.
     * the url /member/transfer
     * the view in index.ftl
     *
     * 显示会员所有可转让的产品数据
     *
     */
    public void index() {
        Member member = SecurityKit.getLoginUser(getRequest());
        int mid = member.getNumber(StringPool.PK_COLUMN).intValue();

        int page = getParaToInt("page", 1);
        int pageSize = getParaToInt("pageSize", Const.PAGE);


        Page<MemberProduct> paginate = dao.paginate(page, pageSize,
                SqlKit.sql("memberproduct.front_select"),
                String.format(SqlKit.sql("memberproduct.front_where_transferable"),
                        TRANSFER_AUDIT, TRANSFER_AUDIT_SUCCESS, TRANSFER_TRADE_SUCCESS, TRANSFER_TRADE_FAIL), mid);
        setAttr("data",paginate);
    }


    /**
     * 撤销转让
     */
    public void revocation(){
        int memberProductId = getParaToInt(0,0);
        if(memberProductId > 0){

            final MemberProduct memberProduct = MemberProduct.dao.findById(memberProductId);
            int transfer_status = TypeKit.getInt(memberProduct, MemberProduct.FIELD_TRANSFER_STATUS);
            if(transfer_status == MemberConstant.TRANSFER_TRADE_SUCCESS){
                renderAjaxFailure("产品已转让，无法撤销转让！");
                return;
            }


            int productId = TypeKit.getInt(memberProduct, Const.FIELD_PRODUCT);

            final TransferProduct transferProduct = TransferProduct.dao.findByMemberProduct(memberProductId, productId);
            int trades = Order.dao.findByTransferOrder(TypeKit.getInt(transferProduct, StringPool.PK_COLUMN));
            if(trades > 0){
                renderAjaxFailure("十分抱歉已有用户在购买您的产品，无法撤销转让！");
                return;
            }

            transferProduct.set(FIELD_STATUS, TransferConstant.STATUE_CANCEL);
            memberProduct.set(MemberProduct.FIELD_TRANSFER_STATUS, MemberConstant.DEFAULT_STATUS);
            int order_id = TypeKit.getInt(transferProduct, FIELD_ORDER_ID);
            boolean ok;
            if (order_id > 0) {
                final Order order = new Order();
                order.set(StringPool.PK_COLUMN, order_id);
                order.set(FIELD_STATUS, OrderConstant.TRADE_CLOSE);

                ok = Db.tx(new IAtom() {
                    @Override
                    public boolean run() throws SQLException {
                        return memberProduct.update() && transferProduct.update() && order.update();
                    }
                });
            } else {
                ok = Db.tx(new IAtom() {
                    @Override
                    public boolean run() throws SQLException {
                        return memberProduct.update() && transferProduct.update();
                    }
                });
            }
            if (ok) {
                renderAjaxSuccess();
            } else {
                renderAjaxFailure("十分抱歉，产品撤销转让失败");
            }

        } else {
            renderAjaxFailure("十分抱歉，产品撤销转让失败");
        }
    }

    /**
     * 转让第一步，确认转让信息
     */
    public void confirm(){
        int mem_pid = getParaToInt(0, 0);
        MemberProduct memberProduct = dao.findRelationById(mem_pid);
        TransferRule transferRule = TransferRule.dao.findDefault();
        setAttr("mp", memberProduct);

        // 投资本金

        BigDecimal prifit = memberProduct.profit();
        BigDecimal amount = memberProduct.getBigDecimal(Const.FIELD_AMOUNT);
        setAttr("amount", amount.add(prifit));

        //转让时效
        int aging = TypeKit.getInt(transferRule, "aging");
        setAttr("aging", aging);
        float ratio = TypeKit.getFloat(transferRule, "ratio");
        //转让手续费比率
        setAttr("ratio", ratio);
        // 挂单免费时间
        int free_times = TypeKit.getInt(transferRule, "free_times");
        DateTime dateTime = DateTime.now();
        if (free_times > 0) {
            DateTime endTime = dateTime.plusDays(free_times);
            DateTime productDueTime = TypeKit.getDateTime(memberProduct, "due_date");
            if(productDueTime == null){
                Logger.error("产品到期时间不存在，无法继续了");
                renderNull();
                return;
            }
            setAttr("endTime", productDueTime.isBefore(endTime) ? productDueTime.toDate() : endTime.toDate());
            setAttr("beginTime", dateTime.toDate());
        }
        setAttr("free_times", free_times);
        // 挂单费
        setAttr("lodging_fee", transferRule.getNumber("lodging_fee"));
    }


    public void dialog() {
        String p_price = getPara("t_price");
        if (!Validator.isCurrency(p_price)) {
            renderAjaxFailure("请输入正确的转让价格");
            return;
        }

        int mem_pid = getParaToInt("mem_pid", 0);
        BigDecimal t_price = new BigDecimal(p_price);

        if(BigDecimal.ZERO.compareTo(t_price) >= 0){
            renderAjaxFailure("转让价格必须大于0");
            return;
        }

        MemberProduct memberProduct = dao.findRelationById(mem_pid);

        BigDecimal prifit = memberProduct.profit();
        BigDecimal amount = memberProduct.getBigDecimal(Const.FIELD_AMOUNT);
        BigDecimal maxAmount = amount.add(prifit);
        setAttr("amount", maxAmount);
        if (t_price.compareTo(maxAmount) == 1) {
            renderAjaxFailure("转让金额不能大于投资金额[" + amount.toPlainString() + "] + 预期收益 [" + prifit.toPlainString() + "] = " + maxAmount.toPlainString());
            return;
        }
        //转让手续费
        TransferRule transferRule = TransferRule.dao.findDefault();
        BigDecimal fee = TransferRule.transferFee(t_price, transferRule);
        //挂单免费时效
        int free_times = TypeKit.getInt(transferRule, "free_times");
        int aging = TypeKit.getInt(transferRule, "aging");
        Map<String,Object> results = Maps.newHashMap();

        BigDecimal loss;
        if(t_price.compareTo(amount) < 0){
            // 计算 预计亏本金额 = 资产价值-(转让价格＋手续费），如果小于0 表示不亏本
            loss = amount.subtract(t_price.add(fee));
            if(BigDecimal.ZERO.compareTo(loss) > 0){
                loss = BigDecimal.ZERO;
            }
        }  else {
            loss = BigDecimal.ZERO;
        }

        results.put("free_times", free_times);
        results.put("fee", fee);
        results.put("price", t_price);
        results.put("aging", aging);
        results.put("amount", amount);
        results.put("loss", loss);
        results.put("lodging_fee", transferRule.getNumber("lodging_fee"));

        renderAjaxSuccess(results);
    }

    /**
     * 转让第二步，确认合同
     */
    public void contract(){
        //转让产品
        int mem_pid = getParaToInt("mpid", 0);
        //转让价格
        String param_price = getPara("price");
        setAttr("mem_pid", mem_pid);
        setAttr("t_price",param_price);
        setAttr("notes", Notes.dao.findByTransfer());
    }

    /**
     * 转让第三步，安全验证
     */
    public void auth(){

        //转让产品
        int mem_pid = getParaToInt("mpid", 0);
        //转让价格
        String param_price = getPara("price");

        setAttr("mem_pid",mem_pid);
        setAttr("t_price", param_price);
    }

    /**
     * 验证短信等信息
     */
    public void security(){
        // 短信验证码
        String sms_code = getPara(Const.FIELD_CODE);
        if (Strings.isNullOrEmpty(sms_code)) {
            renderAjaxFailure("请输入短信验证码");
            return;
        }

        final Member loginUser = SecurityKit.getLoginUser(getRequest());
        String phone = loginUser.getStr("phone");
        if (!SmsCodeKit.checkTransfer(phone, sms_code)) {
            renderAjaxFailure("短信验证码不正确");
            return;
        }

        // 交易密码
        String password = getPara("pwd");

        if (!Strings.isNullOrEmpty(password)) {
            final int memberId = loginUser.getNumber(StringPool.PK_COLUMN).intValue();
            final Account account = Account.dao.findbyMember(memberId);
            boolean matcher = account.checkTradePwd(password);
            if (matcher) {
                renderAjaxSuccess();
            } else {
                renderAjaxFailure("交易密码不正确");
            }
        } else {
            renderAjaxFailure("交易密码不能为空");
        }
    }

    /**
     * 转让成功
     */
    public void commit(){
        final Member loginUser = SecurityKit.getLoginUser(getRequest());
        final int memberId = loginUser.getId();
        //转让产品
        int mem_pid = getParaToInt("mpid", 0);
        //转让价格
        String param_price = getPara("price");
        BigDecimal t_price = NumberUtils.createBigDecimal(param_price);


        final MemberProduct memberProduct = dao.findRelationToTrsById(mem_pid);
        int transferStatus = TypeKit.getInt(memberProduct, FIELD_TRANSFER_STATUS);
        final int productStatus = TypeKit.getInt(memberProduct, FIELD_PRODUCT_STATUS);
        final int redeemStatus = TypeKit.getInt(memberProduct, FIELD_REDEEM_STATUS);
        if ((productStatus == PRODUCT_FOUND)
                && (transferStatus == DEFAULT_STATUS || transferStatus == TRANSFER_TRADE_FAIL)
                && (redeemStatus == DEFAULT_STATUS)) {

            TransferRule transferRule = TransferRule.dao.findDefault();
            //手续费
            BigDecimal fee = TransferRule.transferFee(t_price, transferRule);
            DateTime now = DateTime.now();


            int product = memberProduct.getNumber(Const.FIELD_PRODUCT).intValue();
            double yield = Product.dao.findById(product).getNumber("yield").doubleValue();

            String product_name = memberProduct.getStr("product_name");
            String product_code = memberProduct.getStr(Const.FIELD_CODE);

            final Order order = OrderService.me.createTransferPushOrder(memberId, product, product_name, product_code, t_price, fee);

            final TransferProduct transferProduct = new TransferProduct();
            transferProduct.set(Const.FIELD_PRODUCT, product);//产品
            transferProduct.set("product_name", product_name);//产品名称
            transferProduct.set("member_product", TypeKit.getInt(memberProduct, StringPool.PK_COLUMN));//会员产品
            transferProduct.set("logo", memberProduct.getStr("logo"));//产品LOGO
            transferProduct.set(Const.FIELD_PRICE, t_price);//转让价格
            transferProduct.set("yield", yield);//转让价格
            transferProduct.set("remaining_days", memberProduct.getNumber("left_day").intValue());//剩余天数
            transferProduct.set("assignor", memberProduct.getNumber(Const.FIELD_MEMBER).intValue());//转让方
            transferProduct.set("assignor_phone", memberProduct.getStr("phone"));//转让方电话
            //持有天数
            transferProduct.set("hold_days", TypeKit.getInt(memberProduct, "have_day"));
            transferProduct.set("handing_charge", fee);//手续费
            transferProduct.set("transfer_date", now);//转让日期
            transferProduct.set("transfer_time", now);//转让时间
            transferProduct.set("put_time", now);//挂单时间
            transferProduct.set(Const.FIELD_CREATE_TIME, now);//创建时间
            transferProduct.set(FIELD_STATUS, TransferConstant.STATUE_TRADING);//

            // 转让形势
            final TranferMode tranferMode = new TranferMode();
            tranferMode
                    .set("mode_type", TransferConstant.MOE_PRICE)//一口价
                    .set("create_time", DateTime.now());
            Db.tx(new IAtom() {
                @Override
                public boolean run() throws SQLException {
                    if (order.save()) {
                        transferProduct.set(FIELD_ORDER_ID, order.getBigDecimal(StringPool.PK_COLUMN));

                        if (transferProduct.save()) {
                            //回写会员理财产品表状态
                            memberProduct.set(FIELD_TRANSFER_STATUS, TRANSFER_AUDIT_SUCCESS);
                            tranferMode.set("tranfer", TypeKit.getInt(transferProduct, StringPool.PK_COLUMN));
                        }

                        return memberProduct.update() && tranferMode.save();
                    }
                    return false;
                }
            });
            setAttr("order", order);
        } else {
            setAttr("error", true);
        }


    }


    /**
     * 发送短信验证码
     */
    public void sendsms(){
        Member member = SecurityKit.getLoginUser(getRequest());
        String phone = member.getStr("phone");
        try{
            SmsKit.transfer(phone);
            renderAjaxSuccess();
        }catch (Exception e){
            renderAjaxFailure();
        }
    }
}